home *** CD-ROM | disk | FTP | other *** search
/ Aminet 43 / Aminet 43 (2001)(GTI - Schatztruhe)[!][Jun 2001].iso / Aminet / comm / tcp / AmiVNC.lha / AmiVNC / amivnc.c < prev    next >
C/C++ Source or Header  |  2001-03-02  |  73KB  |  1,667 lines

  1. // AmiVNC - Amiga experimental VNC server - Protocol ORL version 3.3
  2.  
  3. // Includes ***********************************************
  4. // Needed to compile : SDK Cybergraphx 4.1 & SDK AmiTCP 4.3
  5.  
  6. #include <exec/types.h>
  7. #include <exec/memory.h>
  8.  
  9. #include <intuition/IntuitionBase.h>
  10. #include <intuition/intuition.h>
  11.  
  12. #include <graphics/gfxmacros.h>
  13. #include <graphics/displayinfo.h>
  14. #include <graphics/gfxbase.h>
  15.  
  16. #include <clib/exec_protos.h>
  17. #include <clib/dos_protos.h>
  18. #include <clib/intuition_protos.h>
  19. #include <clib/graphics_protos.h>
  20. #include <clib/utility_protos.h>
  21. #include <clib/alib_protos.h>
  22. #include <clib/commodities_protos.h>
  23. #include <clib/icon_protos.h>
  24.  
  25. #include <dos/dostags.h>
  26.  
  27. #include <sys/ioctl.h>
  28. #include <netinet/in.h>
  29. #include <lineread.h>
  30. #include <netdb.h>
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <unistd.h>
  36. #include <fcntl.h>
  37. #include <ctype.h>
  38. #include <filedefs.h>
  39.  
  40. #include <signal.h>
  41.  
  42. #include <devices/input.h>
  43. #include <devices/inputevent.h>
  44. #include <libraries/commodities.h>
  45.  
  46. #include <clib/socket_protos.h>
  47. #include <clib/netlib_protos.h>
  48.  
  49. #include <proto/socket.h>
  50.  
  51. #ifndef PLANAR
  52. #include <cybergraphx/cybergraphics.h>
  53. #include <proto/cybergraphics.h>
  54. #endif
  55.  
  56. // Specific Includes ***********************************************
  57. #include "rfbproto.h"                   // Structures & constants for VNC protocol
  58. #include "vncauth.h"                    // Prototypes for authentication
  59.  
  60. // Constants ***********************************************
  61. #define FALSE           0               // What's that ?
  62. #define TRUE            1               // And this ?
  63. #define XDC_PORT        5900            // Port # for bind()
  64. #define XDC_TILE        32              // Tile size
  65. #define XDC_C_VBUF      (1L << 0)       // Bitmask for pBuffer allocation
  66. #define XDC_C_MSOCK     (1L << 1)       // Bitmask for listen socket open
  67. #define XDC_C_CSOCK     (1L << 2)       // Bitmask for client socket open
  68. #define XDC_C_MAXDEPTH  4               // Max. raster depth : 4 bytes / pixel
  69. #define XDC_LOGFILE     "T:AmiVNC.log"  // Log file name
  70. #undef  PARANO
  71.  
  72. // Common messages
  73. char XDC_ID[] = "AmiVNC 0.1.0 Mar 1st 2001 (StormC4/GCC)";
  74. char XDC_SEND[] = "send() error";
  75. char XDC_RECV[] = "recv() error";
  76.  
  77. // Global variables ***********************************************
  78. LONG    iDuplicateSocketKey;            // Client socket key for transmitting to child process
  79. ULONG   uOpened = NULL;                 // Opened resources, to be closed on exit
  80. BOOL    bDie = FALSE, *pDie = &bDie;    // TRUE : processes are to exit (Argh, very trashy)
  81. BOOL    bSession = FALSE;               // TRUE : clientsession opened
  82. char    cPassword[MAXPWLEN + 1],        // Password
  83.         *pPreStart = NULL,              // User command to execute when connection accepted
  84.         *pPostStop = NULL;              // User command to execute when session closes
  85. LONG    iMasterSocket,                  // Listening socket for incoming connections
  86.         iClientSocket;                  // Client socket accept()ed
  87. UBYTE   *pBuffer = NULL,                // Reference buffer for screen change detection
  88.         *P2CBuffer = NULL;              // Temp buffer for ReadPixelArray8() in planar2chunky
  89. char    *sPWFile = "S:AmiVNC.pwd";      // Password file name
  90. FILE    *fLog;                          // Logfile
  91. struct  sockaddr_in cliAddr;            // To find client IP address. Must be addressable for getpeername. 
  92. struct  BitMap *pBM = NULL;             // Temp. BitMap for temp. RastPort for p2c
  93. extern  struct IntuitionBase *IntuitionBase;
  94. struct  Library *SocketBase;
  95.  
  96. // Free all resources allocated to a client session ***********************************************
  97. void vCleanSession(char *cMsg, long lCode)
  98. {
  99.     // Tell the child process to exit (as we are the main process,
  100.     // we can use bDie, which is in our address space)
  101.     if (!bDie)
  102.     {
  103.         bDie = TRUE;
  104.         Delay(125);
  105.     }
  106.     
  107.     // Close everything opened
  108.     if (uOpened & XDC_C_VBUF)   { free(pBuffer); pBuffer = NULL; uOpened ^= XDC_C_VBUF; }
  109.  
  110.     if (pBM)                    { FreeBitMap(pBM); pBM = NULL; }
  111.  
  112.     if (P2CBuffer)              { free(P2CBuffer); P2CBuffer = NULL; }
  113.  
  114.     if (uOpened & XDC_C_CSOCK)
  115.     {
  116.         CloseSocket(iClientSocket);
  117.         uOpened ^= XDC_C_CSOCK;
  118.         
  119.         // Execute post-close user command (if any)
  120.         if (bSession && pPostStop)
  121.         {
  122.              char cCommand[128];
  123.              sprintf(cCommand, pPostStop, Inet_NtoA(cliAddr.sin_addr.s_addr));
  124.              SystemTags(cCommand, SYS_Asynch, TRUE, TAG_DONE);
  125.              bSession = FALSE;
  126.         }
  127.     }
  128.     
  129.     fprintf(fLog, "AmiVNC - %s (%ld)\nAmiVNC session closed\n", cMsg, lCode);
  130. }
  131.  
  132. // Free all resources allocated to main process and exit ***********************************************
  133. void vCleanExit(char *cMsg, long lCode)
  134. {
  135.     // Free tooltype ArgArray initialized by ArgArrayInit()
  136.     // ArgArrayDone();
  137.     
  138.     vCleanSession(cMsg, lCode);
  139.     
  140.     if (uOpened & XDC_C_MSOCK) { CloseSocket(iMasterSocket); uOpened ^= XDC_C_MSOCK; }
  141.  
  142.     CloseLibrary(SocketBase);
  143.     
  144.     fprintf(fLog, "AmiVNC halted\n");
  145.     
  146.     if (fLog != stdout) fclose(fLog);
  147.     
  148.     exit(0L);
  149. }
  150.  
  151. // Free all resources allocated to main process and exit ***********************************************
  152. void vCleanSig(int iCode)
  153. {
  154.     vCleanExit("Break CTRL-C", (long) iCode);
  155. }
  156.  
  157. // Authentication ***********************************************
  158. BOOL bAuthentify(void)
  159. {
  160.     char cChallenge[16], cResponse[16];
  161.     CARD32 c32Value;
  162.     BOOL bAuthenticated = TRUE;
  163.     int iCnt, iFile;
  164.  
  165.     // Read encoded password in s:AmiVNC.pwd
  166.     if (!(iFile = open(sPWFile, O_RDONLY, 0)))
  167.     return(FALSE);
  168.     
  169.     iCnt = read(iFile, cPassword, sizeof(cPassword));
  170.  
  171.     close(iFile);
  172.  
  173.     if (iCnt != sizeof(cPassword))
  174.     return(FALSE);
  175.  
  176.     // Decode password
  177.     vncDecryptPasswd(cPassword, cPassword);
  178.  
  179.     // Authenticate the connection, if required
  180.     if (!strlen(cPassword))
  181.     {
  182.         // Send no-auth-required message
  183.         c32Value = rfbNoAuth;
  184.         if (!(-1 == (send(iClientSocket,(char *)&c32Value, sizeof(c32Value), 0))))
  185.             return FALSE;
  186.  
  187.         return(TRUE);
  188.     }
  189.     else
  190.     {
  191.         // Send auth-required message
  192.         c32Value = rfbVncAuth;
  193.         if (-1 == (send(iClientSocket,(char *)&c32Value, sizeof(c32Value), 0)))
  194.             return FALSE;
  195.  
  196.         // Now create a 16-byte challenge
  197.         vncRandomBytes((UBYTE *)cChallenge);
  198.  
  199.         // Send the challenge to the client
  200.         if (-1 == (send(iClientSocket, cChallenge, sizeof(cChallenge), 0)))
  201.             return FALSE;
  202.  
  203.         // Read the response
  204.         if (-1 == (recv(iClientSocket, (UBYTE *) cResponse, sizeof(cResponse), 0)))
  205.             return FALSE;
  206.  
  207.         // Encrypt the challenge bytes
  208.         vncEncryptBytes((UBYTE *)cChallenge, cPassword);
  209.  
  210.         // Compare them to the response
  211.         for (iCnt = 0; iCnt < sizeof(cChallenge); iCnt++)
  212.         {
  213.             if (cChallenge[iCnt] != cResponse[iCnt])
  214.             {
  215.                 bAuthenticated = FALSE;
  216.                 break;
  217.             }
  218.         }
  219.  
  220.         // Did the authentication work?
  221.         if (!bAuthenticated)
  222.         {
  223.             c32Value = rfbVncAuthFailed;
  224.             send(iClientSocket, (char *)&c32Value, sizeof(c32Value), 0);
  225.             return FALSE;
  226.  
  227.         }
  228.         else
  229.         {
  230.             // Tell the client we're ok
  231.             c32Value = rfbVncAuthOK;
  232.             if (-1 == (send(iClientSocket, (char *)&c32Value, sizeof(c32Value), 0)))
  233.                 return FALSE;
  234.  
  235.             return(TRUE);
  236.         }
  237.     }
  238. }
  239.  
  240. // Incoming messages management thread ***********************************************
  241. void __saveds vProcessIncomes(void)
  242. {
  243.     struct IOStdReq *inputReqBlk;
  244.     struct MsgPort *inputPort;
  245.     struct IEPointerPixel MPos;
  246.     struct InputEvent eEvent, *VNCEvent = &eEvent;
  247.     struct Screen *pCurrentScreen;
  248.     ULONG iLock;
  249.     UWORD uQualifier = 0;
  250.     rfbClientToServerMsg sCMsg;
  251.     BOOL bLClick = FALSE, bMClick = FALSE, bRClick = FALSE;
  252.     struct Library *SocketBase;
  253.     LONG iSocketChild;
  254.  
  255.     // We have to reopen bsdsocket.library, because it can not be shared between processes
  256.     // OpenLibrary can not fail since it would have halted the father before creating us.
  257.     if (!(SocketBase = OpenLibrary("bsdsocket.library", 4L)))
  258.     {
  259.         fprintf(fLog, "vProcessIncomes : cannot reopen bsdsocket.library\n");
  260.         *pDie = TRUE;
  261.         goto _Nolib;
  262.     }
  263.  
  264.     // Obtain the client socket descriptor from the key saved for us by our father
  265.     if (-1 == (iSocketChild = ObtainSocket(iDuplicateSocketKey, AF_INET, SOCK_STREAM, 0)))
  266.     {
  267.         fprintf(fLog, "vProcessIncomes : ObtainSocket() error %d\n", (int) Errno());
  268.         *pDie = TRUE;
  269.         goto _Nosock;
  270.     }
  271.  
  272.     fprintf(fLog, "vProcessIncomes runs on socket %d\n", (int) iSocketChild);
  273.  
  274.     // Create input.device message structure
  275.     inputPort = CreatePort(NULL, NULL);
  276.     inputReqBlk = (struct IOStdReq *) CreateExtIO(inputPort, sizeof(struct IOStdReq));
  277.     OpenDevice("input.device", NULL, (struct IORequest *) inputReqBlk, NULL);
  278.     inputReqBlk -> io_Data = (APTR) VNCEvent;
  279.     inputReqBlk -> io_Command = IND_WRITEEVENT;
  280.     inputReqBlk -> io_Flags = 0;
  281.     inputReqBlk -> io_Length = sizeof(struct InputEvent);
  282.     
  283.     // Process incoming messages until main process tells to die.
  284.     // Use pointer to bDie because it is not in our address space...
  285.     while (!*pDie) // VERY VERY dirty way to know we have to exit...
  286.     {
  287.        if (-1 == recv(iSocketChild, (UBYTE *) &sCMsg, 1, 0))
  288.        {
  289.            fprintf(fLog, "vProcessIncomes : recv() error, errno = %d\n", (int) Errno());
  290.            *pDie  = TRUE;
  291.            continue;
  292.        }
  293.        
  294. //       Forbid(); // Leave us handle properly our input event
  295.        switch(sCMsg.type)
  296.        {
  297.            case rfbSetPixelFormat : // 0
  298.            if (sz_rfbSetPixelFormatMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbSetPixelFormatMsg - 1, 0))
  299.            {
  300. #ifdef PARANO
  301.                fprintf(fLog, "C -> S : rfbSetPixelFormat lanbpp %d depth %d bigE %d tc %d redM %d redS %d GreM %d GreS %d BluM %d BluS %d\n",
  302.                   sCMsg.spf.format.bitsPerPixel,
  303.                   sCMsg.spf.format.depth,
  304.                   sCMsg.spf.format.bigEndian,
  305.                   sCMsg.spf.format.trueColour,
  306.                   sCMsg.spf.format.redMax,
  307.                   sCMsg.spf.format.redShift,
  308.                   sCMsg.spf.format.greenMax,
  309.                   sCMsg.spf.format.greenShift,
  310.                   sCMsg.spf.format.blueMax,
  311.                   sCMsg.spf.format.blueShift
  312.                   );
  313. #endif // PARANO
  314.                break;
  315.            }
  316.            
  317.            case rfbFixColourMapEntries : // 1
  318.            if (sz_rfbFixColourMapEntriesMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbFixColourMapEntriesMsg - 1, 0))
  319.            {
  320. #ifdef PARANO
  321.                fprintf(fLog, "C -> S : rfbFixColourMapEntries\n");
  322. #endif // PARANO
  323.                break;
  324.            }
  325.            
  326.            case rfbSetEncodings : // 2
  327.            if (sz_rfbSetEncodingsMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbSetEncodingsMsg - 1, 0))
  328.            {
  329. #ifdef PARANO
  330.                fprintf(fLog, "C -> S : rfbSetEncodings\n");
  331. #endif // PARANO
  332.                break;
  333.            }
  334.            
  335.            case rfbFramebufferUpdateRequest : // 3
  336.            if (sz_rfbFramebufferUpdateRequestMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbFramebufferUpdateRequestMsg - 1, 0))
  337.            {
  338. #ifdef PARANO            
  339.                fprintf(fLog, "C -> S : rfbFramebufferUpdateRequest inc %d x %d y %d w %d h %d\n",
  340.                   sCMsg.fur.incremental,
  341.                   sCMsg.fur.x,
  342.                   sCMsg.fur.y,
  343.                   sCMsg.fur.w,
  344.                   sCMsg.fur.h
  345.                   );
  346. #endif // PARANO            
  347.                break;
  348.            }
  349.            
  350.            case rfbKeyEvent : // 4
  351.            if (sz_rfbKeyEventMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbKeyEventMsg - 1, 0))
  352.            {
  353. #ifdef PARANO
  354.                fprintf(fLog, "C -> S : rfbKeyEvent down %d key %d ('%c')\n",
  355.                   sCMsg.ke.down,
  356.                   sCMsg.ke.key,
  357.                   sCMsg.ke.key
  358.                  );
  359. #endif // PARANO
  360.                // Process special keys
  361.                if ((sCMsg.ke.down) && (0xFFE0 == (sCMsg.ke.key & 0xFFE0)))
  362.                {
  363.                    if (sCMsg.ke.key == 0xFFE1) uQualifier |= IEQUALIFIER_LSHIFT;  // Left Shift
  364.                    if (sCMsg.ke.key == 0xFFE2) uQualifier |= IEQUALIFIER_RSHIFT;  // Right Shift
  365.                    if (sCMsg.ke.key == 0xFFE3) uQualifier |= IEQUALIFIER_CONTROL; // Left Control
  366.                    if (sCMsg.ke.key == 0xFFE4) uQualifier |= IEQUALIFIER_CONTROL; // Right Control
  367.                    if (sCMsg.ke.key == 0xFFE9) uQualifier |= IEQUALIFIER_LALT;    // Left Alt
  368.                    if (sCMsg.ke.key == 0xFFEA) uQualifier |= IEQUALIFIER_RALT;    // Right Alt
  369.                    break;
  370.                }
  371.                
  372.                if ((!sCMsg.ke.down) && (0xFFE0 == (sCMsg.ke.key & 0xFFE0)))
  373.                {
  374.                    if (sCMsg.ke.key == 0xFFE1) uQualifier &= ~IEQUALIFIER_LSHIFT; // Left Shift
  375.                    if (sCMsg.ke.key == 0xFFE2) uQualifier &= ~IEQUALIFIER_RSHIFT; // Right Shift
  376.                    if (sCMsg.ke.key == 0xFFE3) uQualifier &= ~IEQUALIFIER_CONTROL; // Left Control
  377.                    if (sCMsg.ke.key == 0xFFE4) uQualifier &= ~IEQUALIFIER_CONTROL; // Right Control
  378.                    if (sCMsg.ke.key == 0xFFE9) uQualifier &= ~IEQUALIFIER_LALT;    // Left Alt
  379.                    if (sCMsg.ke.key == 0xFFEA) uQualifier &= ~IEQUALIFIER_RALT;    // Right Alt
  380.                    break;
  381.                }
  382.  
  383.                // Do nothing on key release
  384.                if (!sCMsg.ke.down) break;
  385.  
  386.                // Process cursor-related keys
  387.                if (0xFF50 == (sCMsg.ke.key & 0xFF50))
  388.                {
  389.                    VNCEvent -> ie_Class = IECLASS_RAWKEY;
  390.                    VNCEvent -> ie_Qualifier = 0;
  391.                    switch(sCMsg.ke.key & 0x000F)
  392.                    {
  393.                        case 0 : // Home
  394.                            VNCEvent -> ie_Code = 0x3D;
  395.                            break;
  396.                        case 1 : // Left
  397.                            VNCEvent -> ie_Code = 0x4F;
  398.                            break;
  399.                        case 2 : // Up
  400.                            VNCEvent -> ie_Code = 0x4C;
  401.                            break;
  402.                        case 3 : // Right
  403.                            VNCEvent -> ie_Code = 0x4E;
  404.                            break;
  405.                        case 4 : // Down
  406.                            VNCEvent -> ie_Code = 0x4D;
  407.                            break;
  408.                        case 5 : // Page up
  409.                            VNCEvent -> ie_Code = 0x3F;
  410.                            break;
  411.                        case 6 : // Page down
  412.                            VNCEvent -> ie_Code = 0x1F;
  413.                            break;
  414.                        case 7 : // End
  415.                            VNCEvent -> ie_Code = 0x1D;
  416.                            break;
  417.                        default :
  418.                            break;
  419.                    }
  420.                }
  421.                else
  422.                {
  423.                    // Map out other 0xFF'ed keys
  424.                    sCMsg.ke.key &= 0xFF;
  425.                    
  426.                    // Find rawkey event out of key ; if we can not, reject key
  427.                    if (!InvertKeyMap((ULONG) sCMsg.ke.key, VNCEvent, NULL))
  428.                    break;
  429.                }
  430.                
  431.                // Apply qualifier if possible
  432.                if (!strchr("~`#5(89", (int) sCMsg.ke.key)) switch(uQualifier)
  433.                {
  434.                    case IEQUALIFIER_CONTROL :
  435.                    case IEQUALIFIER_LSHIFT :
  436.                    case IEQUALIFIER_RSHIFT :
  437.                        VNCEvent -> ie_Qualifier = uQualifier;
  438.                        break;
  439.                            
  440.                    case IEQUALIFIER_LALT :
  441.                        VNCEvent -> ie_Qualifier = IEQUALIFIER_LCOMMAND;
  442.                        break;
  443.                            
  444.                    case IEQUALIFIER_RALT | IEQUALIFIER_CONTROL :
  445.                        VNCEvent -> ie_Qualifier = IEQUALIFIER_RCOMMAND;
  446.                        break;
  447.                }
  448.                
  449.                // Send key into input.device
  450.                DoIO((struct IORequest *) inputReqBlk);
  451.            break;
  452.            }
  453.            
  454.            case rfbPointerEvent : // 5
  455.            if (sz_rfbPointerEventMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbPointerEventMsg - 1, 0))
  456.            {
  457. #ifdef PARANO
  458.                fprintf(fLog, "C -> S : rfbPointerEvent button %d x %d y %d\r",
  459.                   sCMsg.pe.buttonMask,
  460.                   sCMsg.pe.x,
  461.                   sCMsg.pe.y
  462.                  );
  463. #endif // PARANO
  464.  
  465.                /* Set up InputEvent fields */
  466.                VNCEvent -> ie_NextEvent = NULL;
  467. #if 0
  468.                MPos.iepp_Screen = IntuitionBase -> FirstScreen;
  469.                MPos.iepp_Position.X = sCMsg.pe.x;
  470.                MPos.iepp_Position.Y = sCMsg.pe.y;
  471.  
  472.                VNCEvent -> ie_EventAddress  = (APTR)&MPos;
  473.                VNCEvent -> ie_Class         = IECLASS_NEWPOINTERPOS;
  474.                VNCEvent -> ie_SubClass      = IESUBCLASS_PIXEL;
  475.  
  476.                /* absolute positioning */
  477.                VNCEvent -> ie_Qualifier     = NULL;
  478.                VNCEvent -> ie_Qualifier = uQualifier;
  479. #else
  480.                VNCEvent -> ie_Class         = IECLASS_POINTERPOS;
  481.  
  482.                iLock = LockIBase(0);
  483.                pCurrentScreen = IntuitionBase -> FirstScreen;
  484.                UnlockIBase(iLock);
  485.  
  486.                VNCEvent -> ie_X             = (UWORD) ((float) sCMsg.pe.x * 650. / (float) (
  487. #ifndef PLANAR
  488.                                                         GetCyberMapAttr(pCurrentScreen -> RastPort.BitMap, CYBRMATTR_WIDTH)
  489. #else
  490.                                                         GetBitMapAttr(pCurrentScreen -> RastPort.BitMap, BMA_WIDTH)
  491. #endif
  492.                                                                                          - 1));
  493.  
  494.                VNCEvent -> ie_Y             = (UWORD) ((float) sCMsg.pe.y * 490. / (float) (
  495. #ifndef PLANAR
  496.                                                         GetCyberMapAttr(pCurrentScreen -> RastPort.BitMap, CYBRMATTR_HEIGHT)
  497.  
  498. #else
  499.                                                         GetBitMapAttr(pCurrentScreen -> RastPort.BitMap, BMA_HEIGHT)
  500.  
  501. #endif
  502.                                                                                         - 1));
  503.  
  504.                VNCEvent -> ie_Qualifier = uQualifier;
  505. #endif
  506.                // Process mouse buttons...
  507.                VNCEvent -> ie_Code = IECODE_NOBUTTON;
  508.  
  509.                // Left button
  510.                if ((sCMsg.pe.buttonMask) & 1)
  511.                {
  512.                    if (bLClick)
  513.                         VNCEvent -> ie_Code = IECODE_NOBUTTON;
  514.                    else
  515.                    {
  516.                         bLClick = TRUE; VNCEvent -> ie_Code = IECODE_LBUTTON; uQualifier |= IEQUALIFIER_LEFTBUTTON;
  517.                    }
  518.                }
  519.                else if (bLClick) { bLClick = FALSE; VNCEvent -> ie_Code = IECODE_LBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_LEFTBUTTON; }
  520.  
  521.                // Middle button
  522.                if ((sCMsg.pe.buttonMask) & 2)
  523.                {
  524.                    if (bMClick)
  525.                         VNCEvent -> ie_Code = IECODE_NOBUTTON;
  526.                    else
  527.                    {
  528.                         bMClick = TRUE; VNCEvent -> ie_Code = IECODE_MBUTTON;  uQualifier |= IEQUALIFIER_MIDBUTTON;
  529.                    }
  530.                }
  531.                else if (bMClick) { bMClick = FALSE; VNCEvent -> ie_Code = IECODE_MBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_MIDBUTTON; }
  532.  
  533.                // Right button
  534.                if ((sCMsg.pe.buttonMask) & 4)
  535.                {
  536.                    if (bRClick)
  537.                         VNCEvent -> ie_Code = IECODE_NOBUTTON;
  538.                    else
  539.                    {
  540.                         bRClick = TRUE; VNCEvent -> ie_Code = IECODE_RBUTTON;  uQualifier |= IEQUALIFIER_RBUTTON;
  541.                    }
  542.                }
  543.                else if (bRClick) { bRClick = FALSE; VNCEvent -> ie_Code = IECODE_RBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_RBUTTON; }
  544.  
  545.                // Insert event into input.device stream
  546.                DoIO((struct IORequest *) inputReqBlk);
  547.                break;
  548.            }
  549.            
  550.            case rfbClientCutText : // 6
  551.            if (sz_rfbClientCutTextMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbClientCutTextMsg - 1, 0))
  552.            {
  553.                char *cText = (char *) malloc((unsigned) (sCMsg.cct.length + 1));
  554.                recv(iSocketChild, (UBYTE *) cText, (int) (sCMsg.cct.length), 0);
  555.                cText[sCMsg.cct.length] = 0;
  556. #ifdef PARANO
  557.                fprintf(fLog, "C -> S : rfbClientCutText '%s'\n", cText);
  558. #endif // PARANO
  559.                break;
  560.            }
  561.            
  562.            default :
  563. #ifdef PARANO
  564.            fprintf(fLog, "vProcessIncomes : msg type %d unknown\n", sCMsg.type);
  565. #endif // PARANO
  566.            break;
  567.        }
  568. //       Permit();
  569.     }
  570.     
  571.     CloseSocket(iSocketChild);
  572.  
  573.     if (inputReqBlk)
  574.     {
  575.         CloseDevice((struct IORequest *) inputReqBlk);
  576.         DeleteExtIO((struct IORequest *) inputReqBlk);
  577.     }
  578.     
  579.     if (inputPort) DeletePort(inputPort);
  580.  
  581. _Nosock:
  582.     CloseLibrary(SocketBase);
  583.  
  584. _Nolib:
  585.     fprintf(fLog, "vProcessIncomes halted\n");   
  586. }
  587.  
  588. // Main entry point  ***********************************************
  589. int main(int argc, char **argv)
  590. {
  591.     register int iCnt, jCnt;
  592.     BPTR pFile;
  593.     int iMajor, iMinor, iWidth, iHeight, iDepth, iSize, iMode, iPort, iUpdate = 0, iRShift = 8, iGShift = 16, iBShift = 24;
  594.     unsigned long uLimit = 0xFFFFFFFF, uSize, uCnt, uTotal;
  595.     struct sockaddr_in sAddr;                  // Local address for bind()
  596.     struct Screen *pActiveScreen, *pNewScreen;
  597.     rfbProtocolVersionMsg mProtVerMsg;
  598.     rfbServerInitMsg mSerInitMsg;
  599.     rfbFramebufferUpdateMsg mFBUpdMsg;
  600.     rfbFramebufferUpdateRectHeader mFBRMsg;
  601.     long iDelay = 50;
  602.     CARD8 c8;
  603.     BOOL bBig = FALSE, bFastMode, bPlanar, bVVA = FALSE;
  604.     register UBYTE *pRaster;                                    // True WB screen raster
  605.     static UBYTE uTile[XDC_TILE * XDC_TILE * XDC_C_MAXDEPTH];   // 3 Byte/pixel RGB Raster tile for client screen updates
  606.     static UBYTE uCTile[XDC_TILE * XDC_TILE];                   // Chunky tile for planar comparisons 
  607.     char cLog[80], *pC;
  608.     ULONG uLock;
  609.     UBYTE **ArgArray;
  610.     UWORD  CLUT[256];                                           // 16 bit Planar2Chunky color lookup table (pen number -> RGB16PC values)
  611.     UBYTE  CLUT8[256];                                          // 8 bit Planar2Chunky color lookup table (pen number -> BGR233 values)
  612.     struct RastPort TempRP;                                     // Temp. RastPort for ReadPixelArray8
  613.  
  614. #ifndef PLANAR
  615.     struct Library *CGXlib = OpenLibrary("cgxsystem.library", 40L);
  616. #endif
  617.  
  618.     fLog = stdout;
  619.  
  620.     if (!(SocketBase = OpenLibrary("bsdsocket.library", 4L)))
  621.     {
  622.         fprintf(fLog, "main : cannot open bsdsocket.library\n");
  623.         exit;
  624.     }
  625.  
  626.     iPort = XDC_PORT;
  627.     
  628.     strcpy(cLog, XDC_LOGFILE);
  629.  
  630.     signal(SIGINT, vCleanSig);
  631.     
  632.     // Process AmiVNC icon tooltypes
  633. #ifndef __PPC__
  634.     ArgArray = ArgArrayInit((long) argc, (UBYTE **) argv);
  635.     if (pC =  FindToolType(ArgArray, "PORT"))      iPort = atoi(pC);
  636.     if (pC =  FindToolType(ArgArray, "BIGENDIAN")) bBig = (tolower(*pC) == 't') ? TRUE : FALSE;
  637.     if ((pC = FindToolType(ArgArray, "LIMIT")) && (atoi(pC))) uLimit = atoi(pC);
  638.     if (pC =  FindToolType(ArgArray, "RSHIFT"))    iRShift = atoi(pC);
  639.     if (pC =  FindToolType(ArgArray, "GSHIFT"))    iGShift = atoi(pC);
  640.     if (pC =  FindToolType(ArgArray, "BSHIFT"))    iBShift = atoi(pC);
  641.     if (pC =  FindToolType(ArgArray, "LOGFILE"))   strcpy(cLog, pC);
  642.     if (pC =  FindToolType(ArgArray, "PRESTART"))  pPreStart = pC;
  643.     if (pC =  FindToolType(ArgArray, "POSTSTOP"))  pPostStop = pC;
  644.     if (pC =  FindToolType(ArgArray, "VERBOSE"))   cLog[0] = 0;
  645.     if (pC =  FindToolType(ArgArray, "VVA"))       bVVA = TRUE;
  646.     if (pC =  FindToolType(ArgArray, "DELAY"))     iDelay = atoi(pC);
  647. #endif
  648.  
  649.     // Process command line arguments (if any)
  650.     if (argc > 1) while (*++argv)
  651.     {
  652.         switch(tolower((*argv)[1]))
  653.         {
  654.             // *** Force password change and exit
  655.             case 'p' :
  656.                 strncpy(cPassword, *argv + 2, MAXPWLEN);
  657.                 cPassword[MAXPWLEN] = '\0';
  658.                 
  659.                 pC = strchr(cPassword, ' ');
  660.                 if (pC) *pC = '\0';
  661.                 
  662.                 for (iCnt = strlen(cPassword) ; iCnt < MAXPWLEN ; iCnt++)
  663.                    cPassword[iCnt] = '\0';
  664.                 
  665.                 vncEncryptPasswd(cPassword, cPassword);
  666.                 
  667.                 if (!(pFile = Open(sPWFile, MODE_NEWFILE)))
  668.                     vCleanExit("main : creat('s:AmiVNC.pwd') error", 0);
  669.  
  670.                 Write(pFile, cPassword, sizeof(cPassword));
  671.                 Close(pFile);
  672.                 
  673.                 vCleanExit("main : Passwd stored", 0);
  674.                 break;
  675.             
  676.             // *** Force another port than the default 5900
  677.             case 's' :
  678.                 iPort = atoi(*argv + 2);
  679.                 break;
  680.             
  681.             // *** Force BigEndian flag in mSerInitMsg
  682.             case 'e' :
  683.                 bBig = TRUE;
  684.                 break;
  685.             
  686.             // *** Limit netblocksize for initial screen update
  687.             case 'l' :
  688.                 uLimit = atoi(*argv + 2);
  689.                 break;
  690.                 
  691.             // *** Force Red / Green / Blue bitshifts in mSerInitMsg
  692.             // (play with this if you have color problems, legal values
  693.             // for shifts are 0, 8, 16 and 24)
  694.             case 'r' :
  695.                 iRShift = atoi(*argv + 2);
  696.                 break;
  697.                 
  698.             case 'g' :
  699.                 iGShift = atoi(*argv + 2);
  700.                 break;
  701.                 
  702.             case 'b' :
  703.                 iBShift = atoi(*argv + 2);
  704.                 break;
  705.                 
  706.             // Force verbose mode to sdtout
  707.             case 'v' :
  708.                 cLog[0] = 0;
  709.                 break;
  710.                 
  711.             // Force VVA compatible (BGR233) pixel encoding
  712.             case 'a' :
  713.                 bVVA = TRUE;
  714.                 break;
  715.  
  716.             // *** Force delay between screen scans
  717.             case 'd' :
  718.                 iDelay = atoi(*argv + 2);
  719.                 break;
  720.  
  721.             default :
  722.                 printf("main : Arg [%s] ignored\n", *argv);
  723.                 break;
  724.         }
  725.     }
  726.     
  727.     // If log not forced to stdout, open log file
  728.     if (cLog[0])
  729.     {
  730.         fLog = fopen(cLog, "w");
  731.         if (!fLog)
  732.         {
  733.             fLog = stdout;
  734.             vCleanExit("main : Log file open error", 0);
  735.         }
  736.     }
  737.  
  738.     // Welcome...
  739.     fprintf(fLog, "%s\n(c) 1999-2001 stephane.guillard@steria.fr\n", XDC_ID);
  740. #ifdef PLANAR
  741.     fprintf(fLog, "Planar only version\n");
  742. #endif
  743.     
  744.     // Print configurable parameter values
  745.     fprintf(fLog, "main : parameter values :\n");
  746.     fprintf(fLog, " - listen port set to %d\n", iPort);
  747.     fprintf(fLog, " - endian set to %s\n", bBig ? "big" : "little");
  748.     fprintf(fLog, " - initial xfer limit set to %08lX\n", uLimit);
  749.     fprintf(fLog, " - color bitshifts : red %d, green %d, blue %d\n", iRShift, iGShift, iBShift);
  750.     fprintf(fLog, " - log file set to %s\n", cLog[0] ? cLog : "stdout");
  751.     fprintf(fLog, " - VVA BGR233 encoding : %s\n", bVVA ? "yes" : "no");
  752.     fprintf(fLog, " - user command on client login : %s\n", pPreStart ? pPreStart : "none");
  753.     fprintf(fLog, " - user command on client logout : %s\n", pPostStop ? pPostStop : "none");
  754.     
  755.     // Prepare listener socket
  756.     fprintf(fLog, "main : Creating listener socket\n");
  757.     if (-1 == (iMasterSocket = socket(AF_INET, SOCK_STREAM, 0)))
  758.         vCleanExit("main : socket() error", Errno());
  759.     
  760.     uOpened |= XDC_C_MSOCK;
  761.     
  762.     sAddr.sin_family=AF_INET;
  763.     sAddr.sin_addr.s_addr = 0;
  764.     sAddr.sin_port = htons(iPort);
  765.     
  766.     fprintf(fLog, "main : Binding socket on port %d\n", sAddr.sin_port);
  767.     if (-1 == (bind(iMasterSocket, (struct sockaddr *) &sAddr, sizeof(sAddr))))
  768.         vCleanExit("main : bind() error", Errno());
  769.     
  770.     fprintf(fLog, "main : Listening set on port %d\n", sAddr.sin_port);
  771.     if (-1 == (listen(iMasterSocket, 4)))
  772.         vCleanExit("main : listen() error", Errno()); 
  773.  
  774. _NewSession:
  775.  
  776.     bDie = FALSE;
  777.     
  778.     // Wait for incoming connection and find client IP address (use iDuplicateSocketKey
  779.     // as temp. var because at this point it is useless)
  780.     fprintf(fLog, "main : Waiting for client connection\n");
  781.  
  782.     iDuplicateSocketKey = sizeof(cliAddr);
  783.     if (-1 == (iClientSocket = accept(iMasterSocket, (struct sockaddr *) &cliAddr, &iDuplicateSocketKey)))
  784.         vCleanExit("main : accept() error", Errno());
  785.     
  786.     uOpened |= XDC_C_CSOCK;
  787.     
  788.     // Now useless : getpeername(iClientSocket, (struct sockaddr *) &cliAddr, &iDuplicateSocketKey);
  789.  
  790.     fprintf(fLog, "main : accept()ed connection from %s on socket %d\n", Inet_NtoA(cliAddr.sin_addr.s_addr), (int) iClientSocket);
  791.     
  792.     // NegociateProtocolVersion
  793.     fprintf(fLog, "main : Negociating protocol version\n");
  794.     sprintf((char *) mProtVerMsg, rfbProtocolVersionFormat,
  795.     rfbProtocolMajorVersion,
  796.     rfbProtocolMinorVersion);
  797.     if (-1 == (send(iClientSocket, (UBYTE *) mProtVerMsg, sz_rfbProtocolVersionMsg, 0)))
  798.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  799.     
  800.     mProtVerMsg[12] = 0;
  801.  
  802.     if (-1 == (recv(iClientSocket, mProtVerMsg, sz_rfbProtocolVersionMsg, 0)))
  803.     { vCleanSession(XDC_RECV, Errno()); goto _NewSession; }
  804.  
  805.     sscanf((char *) mProtVerMsg, rfbProtocolVersionFormat, &iMajor, &iMinor);
  806.     fprintf(fLog, "main : Protocol supported by server : %d.%d, by client : %d.%d\n", rfbProtocolMajorVersion, rfbProtocolMinorVersion, iMajor, iMinor);
  807.  
  808.     // Check protocol version
  809.     if (iMajor > rfbProtocolMajorVersion)
  810.     { vCleanSession("main : unknown protocol", 0); goto _NewSession; }
  811.     
  812.     // Authenticate DES
  813.     fprintf(fLog, "main : Authentication\n");
  814.     if (FALSE == bAuthentify())
  815.     { vCleanSession("main : Authenticate error", 0); goto _NewSession; }
  816.     
  817.     // ClientInit
  818.     fprintf(fLog, "main : ClientInitialisation\n");
  819.     if (-1 == (recv(iClientSocket, &c8, sizeof(c8), 0)))
  820.     { vCleanSession(XDC_RECV, Errno()); goto _NewSession; }
  821.     
  822.     fprintf(fLog, "main : SharedFlag = %d (multiple clients : %s)\n", c8, c8 ? "Yes" : "No");
  823.  
  824.     // Grab active screen
  825.     pActiveScreen = IntuitionBase -> FirstScreen;
  826.  
  827.     // Check if planar Amiga screen
  828.     bPlanar = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_FLAGS) & BMF_STANDARD ? TRUE : FALSE;
  829.  
  830.     fprintf(fLog, "main : Screen set to [%s] (%s)\n", pActiveScreen -> Title, bPlanar ? "planar" : "RTG");
  831.  
  832.     // Get screen info (mode, width, height, depth, linear address)
  833.     if (!bPlanar) // RTG chunky linear modes
  834.     {
  835. #ifndef PLANAR
  836.         if (GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_ISCYBERGFX)
  837.          && GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_ISLINEARMEM))
  838.         {
  839.             // Get screenmode, width, height, depth
  840.             iMode   = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_PIXFMT);
  841.             iWidth  = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_WIDTH); // X size
  842.             iHeight = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_HEIGHT); // Y size
  843.             iDepth  = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_BPPIX); // Depth is in Bytes / pixel
  844.  
  845.             // Grab chunky raster pointer (dirty but EFFICIENT !)
  846.             UnLockBitMap(LockBitMapTags(pActiveScreen -> RastPort.BitMap,
  847.                      (ULONG) LBMI_BASEADDRESS, (ULONG) &uCnt,
  848.                      TAG_DONE));
  849.             pRaster = (UBYTE *) uCnt;
  850.  
  851.             // Calculate total byte size of screen raster (adjust to 2 byte / pixel if CLUT, will realloc later)
  852.             iSize = iWidth * iHeight * (iDepth > 1 ? iDepth : 2);
  853.             
  854.             fprintf(fLog, "main : RTG mode %s/%ld ", CGXlib ? "CGFx" : "Pic96", (LONG) iMode);
  855.         }
  856.         else // mode unsupported (neither planar neither RTG chunky linear)
  857. #endif
  858.         { vCleanSession("main : screenmode not supported", 0); goto _NewSession; }
  859.     }
  860.     else // planar (non-RTG Amiga Classic chipset planar modes)
  861.     {
  862.         // Get width, height, depth
  863. #ifndef PLANAR
  864.         iMode = 0xFF; // To remember this is a non-RTG screen to set up frame buffer format for ServerInit
  865. #endif
  866.         iWidth  = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_WIDTH); // X size
  867.         iHeight = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_HEIGHT); // Y size
  868.         iDepth  = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_DEPTH); // Depth is in Bits / pixel
  869.         
  870.         // Force size to 2 X Y (each planar pixel will be sent as a 2 byte RGB4 chunky pixel)
  871.         iSize = iWidth * iHeight * (bVVA ? 1 : 2); 
  872.         
  873.         // Screen memory is not linear addressable (but we rather have a raster per bitplane)
  874.         pRaster = NULL;
  875.         
  876.         fprintf(fLog, "main : planar mode ");
  877.     }
  878.  
  879.     fprintf(fLog, "@ 0x%08lX, %dx%d, %d %cpp, size %d\n", (ULONG) pRaster, iWidth, iHeight, iDepth, bPlanar ? 'b' : 'B', bPlanar ? iWidth * iHeight * iDepth / 8 : iSize);
  880.  
  881.     // Fast mode : 2 byte pixel buffer :
  882.     // - planar Amiga screens
  883.     //   OR
  884.     // - Picasso96 AND 2 byte pixels
  885.     //   OR
  886.     // - 1 byte RTG CLUT pixels
  887. #ifndef PLANAR
  888.     bFastMode = ((bPlanar) || ((!CGXlib) && (iDepth == 2)) || ((!bPlanar) && (iDepth == 1)));
  889. #else
  890.     bFastMode = TRUE;
  891. #endif
  892.  
  893.     // Allocate pBuffer (reference buffer for screen compare)
  894.     // - with the screen size if no VVA, and ((under P96 and Depth < 3) OR if planar)
  895.     // - with 4 byte / pixel size if under CGFx or Depth >= 3 or VVA
  896.     if (bVVA)
  897.     {
  898.         if (!(pBuffer = malloc((unsigned) ((bPlanar || (iDepth == 1)) ? iWidth * iHeight : iWidth * iHeight * XDC_C_MAXDEPTH))))
  899.             { vCleanSession("main : malloc() error", 0); goto _NewSession; }
  900.     }
  901.     else
  902.         if (!(pBuffer = malloc((unsigned) (bFastMode ? iSize : iWidth * iHeight * XDC_C_MAXDEPTH))))
  903.             { vCleanSession("main : malloc() error", 0); goto _NewSession; }
  904.    
  905.     uOpened |= XDC_C_VBUF;
  906.     
  907.     // ServerInit : prepare RGB encodings
  908.     // if client is VVA, force encoding as BGR233 in all cases, as VVA only knows this encoding
  909.     if (bVVA)
  910.     {
  911.         mSerInitMsg.format.bitsPerPixel = 8;
  912.         mSerInitMsg.format.depth = 8;
  913.         mSerInitMsg.format.bigEndian = FALSE;
  914.         mSerInitMsg.format.trueColour = TRUE;
  915.         mSerInitMsg.format.redMax = 7;
  916.         mSerInitMsg.format.greenMax = 7;
  917.         mSerInitMsg.format.blueMax = 3;
  918.         mSerInitMsg.format.redShift = 0;
  919.         mSerInitMsg.format.greenShift = 3;
  920.         mSerInitMsg.format.blueShift = 6;
  921.     }
  922.     else
  923. #ifndef PLANAR
  924.         if (bFastMode)
  925.         {
  926.             switch(iMode)
  927.             {
  928.                 case PIXFMT_RGB16PC : // TESTED OK /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: gggbbbbbrrrrrggg */
  929.                     mSerInitMsg.format.bitsPerPixel = 16;
  930.                     mSerInitMsg.format.depth = 16;
  931.                     mSerInitMsg.format.bigEndian = TRUE;
  932.                     mSerInitMsg.format.trueColour = TRUE;
  933.                     mSerInitMsg.format.redMax = 31;
  934.                     mSerInitMsg.format.greenMax = 63;
  935.                     mSerInitMsg.format.blueMax = 31;
  936.                     mSerInitMsg.format.redShift = 11;
  937.                     mSerInitMsg.format.greenShift = 5;
  938.                     mSerInitMsg.format.blueShift = 0;
  939.                     break;
  940.                 case PIXFMT_RGB15PC :        /* HiColor15 (5 bit each), format: gggbbbbb0rrrrrgg */
  941.                     mSerInitMsg.format.bitsPerPixel = 16;
  942.                     mSerInitMsg.format.depth = 15;
  943.                     mSerInitMsg.format.bigEndian = TRUE;
  944.                     mSerInitMsg.format.trueColour = TRUE;
  945.                     mSerInitMsg.format.redMax = 31;
  946.                     mSerInitMsg.format.greenMax = 31;
  947.                     mSerInitMsg.format.blueMax = 31;
  948.                     mSerInitMsg.format.redShift = 10;
  949.                     mSerInitMsg.format.greenShift = 5;
  950.                     mSerInitMsg.format.blueShift = 0;
  951.                     break;
  952.                 case PIXFMT_RGB16 :          /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: rrrrrggggggbbbbb */
  953.                     mSerInitMsg.format.bitsPerPixel = 16;
  954.                     mSerInitMsg.format.depth = 16;
  955.                     mSerInitMsg.format.bigEndian = FALSE;
  956.                     mSerInitMsg.format.trueColour = TRUE;
  957.                     mSerInitMsg.format.redMax = 31;
  958.                     mSerInitMsg.format.greenMax = 63;
  959.                     mSerInitMsg.format.blueMax = 31;
  960.                     mSerInitMsg.format.redShift = 11;
  961.                     mSerInitMsg.format.greenShift = 5;
  962.                     mSerInitMsg.format.blueShift = 0;
  963.                     break;
  964.                 case PIXFMT_RGB15 :          /* HiColor15 (5 bit each), format: 0rrrrrgggggbbbbb */
  965.                     mSerInitMsg.format.bitsPerPixel = 16;
  966.                     mSerInitMsg.format.depth = 15;
  967.                     mSerInitMsg.format.bigEndian = FALSE;
  968.                     mSerInitMsg.format.trueColour = TRUE;
  969.                     mSerInitMsg.format.redMax = 31;
  970.                     mSerInitMsg.format.greenMax = 31;
  971.                     mSerInitMsg.format.blueMax = 31;
  972.                     mSerInitMsg.format.redShift = 10;
  973.                     mSerInitMsg.format.greenShift = 5;
  974.                     mSerInitMsg.format.blueShift = 0;
  975.                     break;
  976.                 case PIXFMT_BGR16PC :        /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: gggrrrrrbbbbbggg */
  977.                     mSerInitMsg.format.bitsPerPixel = 16;
  978.                     mSerInitMsg.format.depth = 16;
  979.                     mSerInitMsg.format.bigEndian = TRUE;
  980.                     mSerInitMsg.format.trueColour = TRUE;
  981.                     mSerInitMsg.format.redMax = 31;
  982.                     mSerInitMsg.format.greenMax = 63;
  983.                     mSerInitMsg.format.blueMax = 31;
  984.                     mSerInitMsg.format.redShift = 0;
  985.                     mSerInitMsg.format.greenShift = 5;
  986.                     mSerInitMsg.format.blueShift = 11;
  987.                     break;
  988.                 case PIXFMT_BGR15PC :        /* HiColor15 (5 bit each), format: gggrrrrr0bbbbbbgg */
  989.                     mSerInitMsg.format.bitsPerPixel = 16;
  990.                     mSerInitMsg.format.depth = 15;
  991.                     mSerInitMsg.format.bigEndian = TRUE;
  992.                     mSerInitMsg.format.trueColour = TRUE;
  993.                     mSerInitMsg.format.redMax = 31;
  994.                     mSerInitMsg.format.greenMax = 31;
  995.                     mSerInitMsg.format.blueMax = 31;
  996.                     mSerInitMsg.format.redShift = 0;
  997.                     mSerInitMsg.format.greenShift = 5;
  998.                     mSerInitMsg.format.blueShift = 10;
  999.                     break;
  1000.                 case PIXFMT_BGR16 :        /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: bbbbbggggggrrrrr */
  1001.                     mSerInitMsg.format.bitsPerPixel = 16;
  1002.                     mSerInitMsg.format.depth = 16;
  1003.                     mSerInitMsg.format.bigEndian = FALSE;
  1004.                     mSerInitMsg.format.trueColour = TRUE;
  1005.                     mSerInitMsg.format.redMax = 31;
  1006.                     mSerInitMsg.format.greenMax = 63;
  1007.                     mSerInitMsg.format.blueMax = 31;
  1008.                     mSerInitMsg.format.redShift = 0;
  1009.                     mSerInitMsg.format.greenShift = 5;
  1010.                     mSerInitMsg.format.blueShift = 11;
  1011.                     break;
  1012.                 case PIXFMT_BGR15 :        /* HiColor15 (5 bit each), format: 0bbbbbbgggggrrrrr */
  1013.                     mSerInitMsg.format.bitsPerPixel = 16;
  1014.                     mSerInitMsg.format.depth = 15;
  1015.                     mSerInitMsg.format.bigEndian = FALSE;
  1016.                     mSerInitMsg.format.trueColour = TRUE;
  1017.                     mSerInitMsg.format.redMax = 31;
  1018.                     mSerInitMsg.format.greenMax = 31;
  1019.                     mSerInitMsg.format.blueMax = 31;
  1020.                     mSerInitMsg.format.redShift = 0;
  1021.                     mSerInitMsg.format.greenShift = 5;
  1022.                     mSerInitMsg.format.blueShift = 10;
  1023.                     break;
  1024.             
  1025.                 case PIXFMT_LUT8 :          /* Chunky CLUT screens, or ... */
  1026.                 case 0xFF :                 /* planar screens : send 2 byte pixels,aligned as per GetRGB4 : 0000RRRR GGGGBBBB*/
  1027. #endif
  1028.                 {
  1029.                     mSerInitMsg.format.bitsPerPixel = 16;
  1030.                     mSerInitMsg.format.depth = 12;
  1031.                     mSerInitMsg.format.bigEndian = FALSE;
  1032.                     mSerInitMsg.format.trueColour = TRUE;
  1033.                     mSerInitMsg.format.redMax = 15;
  1034.                     mSerInitMsg.format.greenMax = 15;
  1035.                     mSerInitMsg.format.blueMax = 15;
  1036.                     mSerInitMsg.format.redShift = 8;
  1037.                     mSerInitMsg.format.greenShift = 4;
  1038.                     mSerInitMsg.format.blueShift = 0;
  1039.                 }
  1040. #ifndef PLANAR
  1041.                     break;
  1042.                 
  1043.                 default :
  1044.                     { vCleanSession("main : RGB mode not supported", 0); goto _NewSession; }
  1045.                     break;
  1046.              }
  1047.         }
  1048.         else // CGFx or Depth > 2 or screen not planar
  1049.              // then use dumb 24 bpp mode, sent as 32 bpp because VNC protocol forbids 3 byte pixels
  1050.         {
  1051.             mSerInitMsg.format.bitsPerPixel = 32;
  1052.             mSerInitMsg.format.depth = 24;
  1053.             mSerInitMsg.format.bigEndian = bBig;
  1054.             mSerInitMsg.format.trueColour = TRUE;
  1055.             mSerInitMsg.format.redMax =
  1056.             mSerInitMsg.format.greenMax =
  1057.             mSerInitMsg.format.blueMax = 255;
  1058.             mSerInitMsg.format.redShift = iRShift;
  1059.             mSerInitMsg.format.greenShift = iGShift;
  1060.             mSerInitMsg.format.blueShift = iBShift;
  1061.         }
  1062. #endif
  1063.     
  1064.     // Finish serverinit and send it
  1065.     mSerInitMsg.framebufferWidth = iWidth;
  1066.     mSerInitMsg.framebufferHeight = iHeight;
  1067.     mSerInitMsg.nameLength = sizeof(XDC_ID);
  1068.  
  1069.     if (-1 == (send(iClientSocket, (UBYTE *) &mSerInitMsg, sizeof(mSerInitMsg), 0)))
  1070.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }    
  1071.  
  1072.     if (-1 == (send(iClientSocket, (UBYTE *) XDC_ID, sizeof(XDC_ID), 0)))
  1073.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1074.  
  1075.     // Initial Screen update : header...
  1076.     mFBUpdMsg.type = rfbFramebufferUpdate;
  1077.     mFBUpdMsg.nRects = 1;
  1078.     if (-1 == (send(iClientSocket, (UBYTE *) &mFBUpdMsg, sizeof(mFBUpdMsg), 0)))
  1079.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1080.     
  1081.     // Initial Screen update : 1 rectangle for whole screen...
  1082.     mFBRMsg.r.x = 0;
  1083.     mFBRMsg.r.y = 0;
  1084.     mFBRMsg.r.w = iWidth;
  1085.     mFBRMsg.r.h = iHeight;
  1086.     mFBRMsg.encoding = rfbEncodingRaw;
  1087.  
  1088.     if (-1 == (send(iClientSocket, (UBYTE *) &mFBRMsg, sizeof(mFBRMsg), 0)))
  1089.     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1090.  
  1091.     // Copy raster into buffer for send() and for ulterior compares
  1092.     if ((bFastMode) && (!bVVA)) // Planar or Pic96/2 byte pixels, no VVA
  1093.     {
  1094. #ifndef PLANAR
  1095.         if (bPlanar)   // planar screen
  1096.         {
  1097. #endif
  1098.             // We have to :
  1099.             // - ReadPixelArray8 the whole screen,
  1100.             // - make a (256 entries max.) color lookup table (CLUT) out of screen colormap
  1101.             // - Then encode each pixel with GetRGB4 and the CLUT, as a 16 bit pixel array to send to the client
  1102.  
  1103.             P2CBuffer = malloc((unsigned) (iWidth * iHeight)); // 1 byte per pixel : pen number
  1104.  
  1105.             // Allocate bitmap for temp. rastport for ReadPixelArray8()
  1106.             pBM = AllocBitMap((unsigned long) iWidth, (unsigned long) 1, (unsigned long) iDepth,
  1107.                               BMF_CLEAR | BMF_DISPLAYABLE, pActiveScreen -> RastPort.BitMap);    // Temp. BitMap for temp. RastPort
  1108.  
  1109.             // Initialize temporary rastport necessary for ReadPixelArray8()
  1110.             InitRastPort(&TempRP);
  1111.             TempRP.Layer = NULL;
  1112.             TempRP.BitMap = pBM;
  1113.             
  1114.             // Fill color lookup table with ready-to-send 16 bit RGB values
  1115.             jCnt = 1 << iDepth;
  1116.             for (iCnt = 0 ; iCnt < jCnt ; iCnt++)
  1117.             {
  1118.                  ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1119.                  ULONG wR = (lColor >> 8) & 0x0f;
  1120.                  ULONG wG = (lColor >> 4) & 0x0f;
  1121.                  ULONG wB = (lColor >> 0) & 0x0f;
  1122.                  CLUT[iCnt] = (wG << 4 | wB) << 8 | wR;
  1123.             }
  1124.                 
  1125.             // Read our chunky clut-index array from planar raster
  1126.             ReadPixelArray8(&(pActiveScreen -> RastPort),
  1127.                             (unsigned long) 0, (unsigned long) 0, (unsigned long) iWidth - 1, (unsigned long) iHeight - 1,
  1128.                             P2CBuffer,
  1129.                             &TempRP
  1130.                            );
  1131.  
  1132.             // Make up the RBG chunky buffer
  1133.             for (jCnt = 0 ; jCnt < iHeight ; jCnt++)
  1134.                for (iCnt = 0 ; iCnt < iWidth ; iCnt++)
  1135.                    *((UWORD *) (pBuffer + (iCnt + jCnt * iWidth) * 2)) = CLUT[P2CBuffer[iCnt + jCnt * iWidth]];
  1136. #ifndef PLANAR
  1137.         }
  1138.         else
  1139.             if (iDepth == 1) // 8 bit pixels, CLUT, RTG chunky
  1140.             {
  1141.                 // Fill color lookup table with 256 ready-to-send 16 bit RGB values
  1142.                 for (iCnt = 0 ; iCnt < 256 ; iCnt++)
  1143.                 {
  1144.                      ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1145.                      ULONG wR = (lColor >> 8) & 0x0f;
  1146.                      ULONG wG = (lColor >> 4) & 0x0f;
  1147.                      ULONG wB = (lColor >> 0) & 0x0f;
  1148.                      CLUT[iCnt] = (wG << 4 | wB) << 8 | wR;
  1149.                 }
  1150.  
  1151.                 // Make up the RBG chunky buffer
  1152.                 for (jCnt = 0 ; jCnt < iHeight ; jCnt++)
  1153.                    for (iCnt = 0 ; iCnt < iWidth ; iCnt++)
  1154.                        *((UWORD *) (pBuffer + (iCnt + jCnt * iWidth) * 2)) = CLUT[pRaster[iCnt + jCnt * iWidth]];
  1155.             }
  1156.             else // Picasso 96 2 byte pixel screen
  1157.             {
  1158.                 // simply send raster memory (as 16 bit pixels)
  1159.                 memcpy(pBuffer, pRaster, (unsigned) iSize);
  1160.             }
  1161. #endif        
  1162.     }
  1163.     else // neither planar nor CLUT nor Pic96/2byte pixels (thus 3 or more byte pixels or CGFx > 1 Bpp),
  1164.          // or VVA in all cases
  1165.     {
  1166. #ifndef PLANAR
  1167.         if (bPlanar)   // planar screen
  1168.         {
  1169. #endif
  1170.             // We have to :
  1171.             // - ReadPixelArray8 the whole screen,
  1172.             // - make a (256 entries max.) color lookup table (CLUT) out of screen colormap
  1173.             // - Then encode each pixel with GetRGB4 and the CLUT, as a 8 bit BGR233 pixel array to send to the client
  1174.  
  1175.             P2CBuffer = malloc((unsigned) (iWidth * iHeight)); // 1 byte per pixel : pen number
  1176.  
  1177.             // Allocate bitmap for temp. rastport for ReadPixelArray8()
  1178.             pBM = AllocBitMap((unsigned long) iWidth, (unsigned long) 1, (unsigned long) iDepth,
  1179.                               BMF_CLEAR | BMF_DISPLAYABLE, pActiveScreen -> RastPort.BitMap);    // Temp. BitMap for temp. RastPort
  1180.  
  1181.             // Initialize temporary rastport necessary for ReadPixelArray8()
  1182.             InitRastPort(&TempRP);
  1183.             TempRP.Layer = NULL;
  1184.             TempRP.BitMap = pBM;
  1185.             
  1186.             // Fill color lookup table with ready-to-send BGR233 values
  1187.             jCnt = 1 << iDepth;
  1188.             for (iCnt = 0 ; iCnt < jCnt ; iCnt++)
  1189.             {
  1190.                  ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1191.                  UBYTE wR = (lColor >> 9) & 0x07;
  1192.                  UBYTE wG = (lColor >> 5) & 0x07;
  1193.                  UBYTE wB = (lColor >> 2) & 0x03;
  1194.                  CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR;
  1195.             }
  1196.                 
  1197.             // Read our chunky clut-index array from planar raster
  1198.             ReadPixelArray8(&(pActiveScreen -> RastPort),
  1199.                             (unsigned long) 0, (unsigned long) 0, (unsigned long) iWidth - 1, (unsigned long) iHeight - 1,
  1200.                             P2CBuffer,
  1201.                             &TempRP
  1202.                            );
  1203.  
  1204.             // Make up the BGR233 chunky buffer
  1205.             for (jCnt = 0 ; jCnt < iHeight ; jCnt++)
  1206.                for (iCnt = 0 ; iCnt < iWidth ; iCnt++)
  1207.                    pBuffer[iCnt + jCnt * iWidth] = CLUT8[P2CBuffer[iCnt + jCnt * iWidth]];
  1208.             
  1209. #ifndef PLANAR
  1210.         }
  1211.         else
  1212.             if (iDepth == 1) // 8 bit pixels, CLUT, RTG chunky
  1213.             {
  1214.                 // Fill color lookup table with 256 ready-to-send BGR233 values
  1215.                 for (iCnt = 0 ; iCnt < 256 ; iCnt++)
  1216.                 {
  1217.                      ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1218.                      UBYTE wR = (lColor >> 9) & 0x07;
  1219.                      UBYTE wG = (lColor >> 5) & 0x07;
  1220.                      UBYTE wB = (lColor >> 2) & 0x03;
  1221.                      CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR;
  1222.                 }
  1223.  
  1224.                 // Make up the RBG chunky buffer
  1225.                 for (jCnt = 0 ; jCnt < iHeight ; jCnt++)
  1226.                    for (iCnt = 0 ; iCnt < iWidth ; iCnt++)
  1227.                        pBuffer[iCnt + jCnt * iWidth] = CLUT8[pRaster[iCnt + jCnt * iWidth]];
  1228.             }
  1229.             else // All RTG modes with depth > 1 byte
  1230.             {
  1231.                 // We have to make 4 byte pixels out of the raster
  1232.                 ReadPixelArray(pBuffer,     // Buffer
  1233.                        (UWORD) 0, (UWORD) 0,        // Dest X/Y in buffer
  1234.                        (UWORD) (iWidth * XDC_C_MAXDEPTH),     // Byte width of buffer
  1235.                        & (pActiveScreen -> RastPort),
  1236.                        (UWORD) 0, (UWORD) 0,         // Source X/Y
  1237.                        (UWORD) iWidth, (UWORD) iHeight,  // Source w/h
  1238.                        (UBYTE) RECTFMT_ARGB
  1239.                        );
  1240.  
  1241.                 if (bVVA) // Make up the BGR233 buffer
  1242.                     for (jCnt = 0 ; jCnt < iHeight ; jCnt++)
  1243.                        for (iCnt = 0 ; iCnt < iWidth ; iCnt++)
  1244.                             pBuffer[iCnt + jCnt * iWidth] =
  1245.                                 (pBuffer[(iCnt  + jCnt * iWidth) * 4 + 1] & 0xE0) >> 5 |
  1246.                                 (pBuffer[(iCnt  + jCnt * iWidth) * 4 + 2] & 0xE0) >> 2 |
  1247.                                 (pBuffer[(iCnt  + jCnt * iWidth) * 4 + 3] & 0xC0) >> 0;
  1248.             }
  1249. #endif
  1250.     }
  1251.  
  1252.     // Send buffer (by uLimit packet size if set).
  1253.     uTotal = (bVVA ? iWidth * iHeight : (bFastMode ? iSize : iWidth * iHeight * XDC_C_MAXDEPTH));
  1254.     uSize = (uTotal > uLimit ? uLimit : uTotal);
  1255.     for (uCnt = 0 ; uCnt < uTotal ; uCnt += uSize)
  1256.         if (-1 == (send(iClientSocket, (UBYTE *) pBuffer + uCnt, (int) uSize, 0)))
  1257.         { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1258.  
  1259. #ifndef PLANAR
  1260.     // if CGFx or depth > 2, reallocate the buffer to actual raster size (eg .3 byte / pixel instead of 4)
  1261.     if ((!bFastMode) && (iDepth != 4) && ((iDepth == 3) || (CGXlib)))
  1262.     {
  1263.         // Reallocate the buffer, resizing it to what's really necessary
  1264.         if (!(pBuffer = realloc(pBuffer, (unsigned) iSize)))
  1265.         { vCleanSession("main : realloc() error", 0); goto _NewSession; }
  1266.        
  1267.         // Byte copy the screen into the buffer for fast compare
  1268.         memcpy(pBuffer, pRaster, (unsigned) iSize);
  1269.     }
  1270.  
  1271.     if ((bFastMode) && (!bPlanar) && (bVVA) && (iDepth == 2))
  1272.     {
  1273.         // Reallocate the buffer, resizing it to what's really necessary
  1274.         if (!(pBuffer = realloc(pBuffer, (unsigned) iSize)))
  1275.         { vCleanSession("main : realloc() error", 0); goto _NewSession; }
  1276.        
  1277.         // Byte copy the screen into the buffer for fast compare
  1278.         memcpy(pBuffer, pRaster, (unsigned) iSize);
  1279.     }
  1280.  
  1281.     // if planar, reallocate the buffer to iWidth x iDepth for ReadPixelArray8() and store chunky raster
  1282.     if (bPlanar)
  1283.     {
  1284. #endif
  1285.         // Reallocate the buffer, resizing it to what's really necessary
  1286.         if ((!bVVA) && (!(pBuffer = realloc(pBuffer, (unsigned) (iWidth * iHeight)))))
  1287.         { vCleanSession("main : realloc() error", 0); goto _NewSession; }
  1288.        
  1289.         // Byte copy the screen into the buffer for fast compare
  1290.         memcpy(pBuffer, P2CBuffer, (unsigned) (iWidth * iHeight));
  1291.         
  1292.         // Free P2CBuffer, which from now on is useless
  1293.         free(P2CBuffer);
  1294.         P2CBuffer = NULL;
  1295. #ifndef PLANAR    
  1296.     }
  1297.  
  1298.     // if RTG chunky CLUT, reallocate the buffer to iWidth x iDepth and copy screen raster into it
  1299.     if ((!bPlanar) && (iDepth == 1))
  1300.     {
  1301.         // Reallocate the buffer, resizing it to what's really necessary
  1302.         if ((!bVVA) && (!(pBuffer = realloc(pBuffer, (unsigned) (iWidth * iHeight)))))
  1303.         { vCleanSession("main : realloc() error", 0); goto _NewSession; }
  1304.        
  1305.         // Byte copy the screen into the buffer for fast compare
  1306.         memcpy(pBuffer, pRaster, (unsigned) (iWidth * iHeight));
  1307.     }
  1308. #endif
  1309.     
  1310.     // Preset framebuffer update message X and Y size to XDC_TILE
  1311.     mFBRMsg.r.w =
  1312.     mFBRMsg.r.h = XDC_TILE;
  1313.  
  1314.     // Release a key to the client socket so that child process can grab it
  1315.     if (-1 == (iDuplicateSocketKey = ReleaseCopyOfSocket(iClientSocket, UNIQUE_ID)))
  1316.     { vCleanSession("main : ReleaseCopyOfSocket() error", Errno()); goto _NewSession; }
  1317.  
  1318.     // Create incoming messages handling child process
  1319.     if (!CreateNewProcTags(
  1320.           NP_Entry, vProcessIncomes,
  1321.           NP_StackSize, 32000,
  1322.           NP_Name, "AmiVNC handler",
  1323.           TAG_DONE
  1324.        ))
  1325.     { vCleanSession("main : CreateNewProcTags() error", 0); goto _NewSession; }
  1326.         
  1327.     // Execute user command on accepted connection (if any)
  1328.     if (pPreStart)
  1329.     {
  1330.         char cCommand[128];
  1331.         sprintf(cCommand, pPreStart, Inet_NtoA(cliAddr.sin_addr.s_addr));
  1332.         SystemTags(cCommand, SYS_Asynch, TRUE, TAG_DONE);
  1333.     }
  1334.     
  1335.     // Session is truly opened now
  1336.     bSession = TRUE;
  1337.     
  1338.     // While not end of session (by child or by ourself)
  1339.     while (!bDie)
  1340.     {
  1341.         // If a delay is required, then wait
  1342.         if (iDelay) Delay(iDelay);
  1343.  
  1344.         // Search for active screen change
  1345.         uLock = LockIBase(0);
  1346.         pNewScreen = IntuitionBase -> FirstScreen;
  1347.         UnlockIBase(uLock);
  1348.  
  1349.         if (pNewScreen != pActiveScreen)
  1350.         {
  1351. #ifndef PLANAR
  1352.             if (bPlanar) // Original Amiga screens
  1353.             {
  1354. #endif
  1355.                 // Check if new screen is also planar and has same dimensions
  1356.                 if ((GetBitMapAttr(pNewScreen -> RastPort.BitMap, BMA_FLAGS) & BMF_STANDARD)
  1357.                  && (iWidth == GetBitMapAttr(pNewScreen -> RastPort.BitMap, BMA_WIDTH)) // X size
  1358.                  && (iHeight == GetBitMapAttr(pNewScreen -> RastPort.BitMap, BMA_HEIGHT))) // Y size
  1359.                 {
  1360.                     // Grab new screen
  1361.                     pActiveScreen = pNewScreen;
  1362.                     fprintf(fLog, "main : Screen set to [%s]\n", pActiveScreen -> Title);
  1363.                     
  1364.                     // Update depth
  1365.                     iDepth = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_DEPTH); // Depth is in Bits / pixel
  1366.                     
  1367.                     // Update CLUT (or CLUT8 if bVVA)
  1368.                     jCnt = 1 << iDepth;
  1369.                     if (bVVA) // BGR233
  1370.                         for (iCnt = 0 ; iCnt < jCnt ; iCnt++)
  1371.                         {
  1372.                              ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1373.                              UBYTE wR = (lColor >> 9) & 0x07;
  1374.                              UBYTE wG = (lColor >> 5) & 0x07;
  1375.                              UBYTE wB = (lColor >> 2) & 0x03;
  1376.                              CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR;
  1377.                         }
  1378.                     else      // RGB16PC
  1379.                         for (iCnt = 0 ; iCnt < jCnt ; iCnt++)
  1380.                         {
  1381.                              ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1382.                              ULONG wR = (lColor >> 8) & 0x0f;
  1383.                              ULONG wG = (lColor >> 4) & 0x0f;
  1384.                              ULONG wB = (lColor >> 0) & 0x0f;
  1385.                              CLUT[iCnt] = (wG << 4 | wB) << 8 | wR;
  1386.                         }
  1387.                 
  1388.                     // Force client screen update (almost :-)
  1389.                     memset(pBuffer, iWidth * iHeight, 0xFF);
  1390.                 }
  1391.                 else
  1392.                 { vCleanSession("main : planar screenmode switch not allowed", 0); goto _NewSession; }
  1393. #ifndef PLANAR
  1394.             } // bPlanar
  1395.             else // Chunky (RTG)
  1396.             {
  1397.                 if (GetCyberMapAttr(pNewScreen -> RastPort.BitMap, CYBRMATTR_ISCYBERGFX)
  1398.                  && GetCyberMapAttr(pNewScreen -> RastPort.BitMap, CYBRMATTR_ISLINEARMEM)
  1399.                  && iWidth == GetCyberMapAttr(pNewScreen -> RastPort.BitMap, CYBRMATTR_WIDTH)
  1400.                  && iHeight == GetCyberMapAttr(pNewScreen -> RastPort.BitMap, CYBRMATTR_HEIGHT)
  1401.                  && iDepth == GetCyberMapAttr(pNewScreen -> RastPort.BitMap, CYBRMATTR_BPPIX))
  1402.                 {
  1403.                     // Grab new screen
  1404.                     pActiveScreen = pNewScreen;
  1405.                     fprintf(fLog, "main : Screen set to [%s]\n", pActiveScreen -> Title);
  1406.                     UnLockBitMap(LockBitMapTags(pActiveScreen -> RastPort.BitMap,
  1407.                          LBMI_BASEADDRESS, (ULONG) &uCnt,
  1408.                          TAG_DONE));
  1409.                     pRaster = (UBYTE *) uCnt;
  1410.                 
  1411.                     // If depth == 1, update CLUT
  1412.                     if (iDepth == 1)
  1413.                     {
  1414.                         if (bVVA) // BGR233
  1415.                             for (iCnt = 0 ; iCnt < 256 ; iCnt++)
  1416.                             {
  1417.                                  ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1418.                                  UBYTE wR = (lColor >> 9) & 0x07;
  1419.                                  UBYTE wG = (lColor >> 5) & 0x07;
  1420.                                  UBYTE wB = (lColor >> 2) & 0x03;
  1421.                                  CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR;
  1422.                             }
  1423.                         else      // RGB16PC
  1424.                             for (iCnt = 0 ; iCnt < 256 ; iCnt++)
  1425.                             {
  1426.                                  ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt);
  1427.                                  ULONG wR = (lColor >> 8) & 0x0f;
  1428.                                  ULONG wG = (lColor >> 4) & 0x0f;
  1429.                                  ULONG wB = (lColor >> 0) & 0x0f;
  1430.                                  CLUT[iCnt] = (wG << 4 | wB) << 8 | wR;
  1431.                             }
  1432.                 
  1433.                         // Force client screen update (almost :-)
  1434.                         memset(pBuffer, iWidth * iHeight, 0xFF);
  1435.                     }
  1436.                 }
  1437.                 else
  1438.                 { vCleanSession("main : chunky screenmode switch not allowed", 0); goto _NewSession; }
  1439.             } // Chunky
  1440. #endif
  1441.         } // pNewScreen != pActiveScreen
  1442.                 
  1443.         // Search for changes in screen...
  1444.         for (jCnt = 0 ; jCnt < iHeight; jCnt += XDC_TILE)
  1445.         {
  1446.             for (iCnt = 0 ; iCnt < iWidth ; iCnt += XDC_TILE)
  1447.             {
  1448.                 register int iYtile, iXtile;
  1449.                 BOOL bChange = FALSE;
  1450. #ifndef PLANAR    
  1451.                 if (!bPlanar) // chunky linear-addressed rasters
  1452.                     for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1453.                     {
  1454.                         if (memcmp((UBYTE *) (pBuffer) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  1455.                            (UBYTE *) (pRaster) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  1456.                            (unsigned) (XDC_TILE * iDepth)))
  1457.                         {
  1458.                             memcpy((UBYTE *) (pBuffer) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  1459.                                (UBYTE *) (pRaster) + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  1460.                                (unsigned) (XDC_TILE * iDepth));
  1461.  
  1462.                             bChange = TRUE;
  1463.                         }
  1464.                     }
  1465.                 else // planar rasters
  1466.                 {
  1467. #endif
  1468.                     // 0 - Once every 10 scans, refresh palette (we have no event here to say palette has changed)
  1469.                     if (!(iUpdate++ % 10))
  1470.                     {
  1471.                         int nColor = 1 << iDepth, iColor;
  1472.                         if (bVVA)
  1473.                             for (iColor = 0 ; iColor < 256 ; iColor++)
  1474.                             {
  1475.                                  ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor);
  1476.                                  UBYTE wR = (lColor >> 9) & 0x07;
  1477.                                  UBYTE wG = (lColor >> 5) & 0x07;
  1478.                                  UBYTE wB = (lColor >> 2) & 0x03;
  1479.                                  CLUT8[iColor] = (wB << 3 | wG) << 3 | wR;
  1480.                             }
  1481.                         else
  1482.                             for (iColor = 0 ; iColor < nColor ; iColor++)
  1483.                             {
  1484.                                  ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor);
  1485.                                  ULONG wR = (lColor >> 8) & 0x0f;
  1486.                                  ULONG wG = (lColor >> 4) & 0x0f;
  1487.                                  ULONG wB = (lColor >> 0) & 0x0f;
  1488.                                  CLUT[iColor] = (wG << 4 | wB) << 8 | wR;
  1489.                             }
  1490.                     }
  1491.                 
  1492.                     // 1 - get a chunky 32x32 1 byte clut entry buffer
  1493.                     ReadPixelArray8(&(pActiveScreen -> RastPort),
  1494.                                     (unsigned long) iCnt, (unsigned long) jCnt, (unsigned long) iCnt + XDC_TILE - 1, (unsigned long) jCnt + XDC_TILE - 1,
  1495.                                     uCTile,
  1496.                                     &TempRP
  1497.                                    );
  1498.                                
  1499.                     // 2 - then compare it to reference buffer. if !=, remember to update client and store new.
  1500.                     for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1501.                     {
  1502.                         if (memcmp((UBYTE *) (pBuffer) + (iCnt + (jCnt + iYtile) * iWidth),
  1503.                                    (UBYTE *) (uCTile) + (iYtile * XDC_TILE),
  1504.                                    XDC_TILE))
  1505.                         {
  1506.                             memcpy((UBYTE *) (pBuffer) + (iCnt + (jCnt + iYtile) * iWidth),
  1507.                                    (UBYTE *) (uCTile) + (iYtile * XDC_TILE),
  1508.                                    XDC_TILE);
  1509.                                
  1510.                             bChange = TRUE;
  1511.                         }
  1512.                     }
  1513. #ifndef PLANAR
  1514.                 }
  1515. #endif
  1516.         
  1517.                 // If change found, send the tile
  1518.                 if (bChange)
  1519.                 {
  1520.                     if (-1 == (send(iClientSocket, (UBYTE *) &mFBUpdMsg, sizeof(mFBUpdMsg), 0)))
  1521.                     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1522.  
  1523.                     mFBRMsg.r.x = iCnt;
  1524.                     mFBRMsg.r.y = jCnt;
  1525.    
  1526.                     // Send framebuffer update header
  1527.                     if (-1 == (send(iClientSocket, (UBYTE *) &mFBRMsg, sizeof(mFBRMsg), 0)))
  1528.                     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1529.  
  1530.                     // Send update data
  1531. #ifndef PLANAR
  1532.                     if (bPlanar)
  1533.                     {
  1534. #endif
  1535.                         if (bVVA)
  1536.                         {
  1537.                             for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1538.                                for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile++)
  1539.                                    uTile[iXtile + iYtile * XDC_TILE] = CLUT8[uCTile[iXtile + iYtile * XDC_TILE]];
  1540.             
  1541.                             // Send framebuffer update pixel data
  1542.                             if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE, 0)))
  1543.                             { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1544.                         }
  1545.                         else
  1546.                         {
  1547.                             for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1548.                                for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile++)
  1549.                                    *((UWORD *) (uTile + (iXtile + iYtile * XDC_TILE) * 2)) = CLUT[uCTile[iXtile + iYtile * XDC_TILE]];
  1550.             
  1551.                             // Send framebuffer update pixel data
  1552.                             if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * 2, 0)))
  1553.                             { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1554.                         }
  1555. #ifndef PLANAR
  1556.                     }
  1557.                     else
  1558.                         if ((!bVVA) && (bFastMode) && (iDepth == 2)) // 2 byte pixels under Pic96 : send directly from buffer (2 is idepth)
  1559.                         {
  1560.                             for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1561.                                memcpy(uTile + XDC_TILE * iYtile * iDepth,
  1562.                                       pRaster + iDepth * (iCnt + (jCnt + iYtile) * iWidth),
  1563.                                       (unsigned) (XDC_TILE * iDepth));
  1564.         
  1565.                             // Send framebuffer update pixel data
  1566.                             if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * 2, 0)))
  1567.                             { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1568.                         }
  1569.                         else
  1570.                             if ((!bVVA) && (iDepth == 1)) // RTG chunky 1 byte pixels
  1571.                             {
  1572.                                 // Every 10 update, refresh color lookup table with 256 ready-to-send 16 bit RGB values
  1573.                                 if (!(iUpdate++ % 10))
  1574.                                 {
  1575.                                     int iColor;
  1576.                                     for (iColor = 0 ; iColor < 256 ; iColor++)
  1577.                                     {
  1578.                                          ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor);
  1579.                                          ULONG wR = (lColor >> 8) & 0x0f;
  1580.                                          ULONG wG = (lColor >> 4) & 0x0f;
  1581.                                          ULONG wB = (lColor >> 0) & 0x0f;
  1582.                                          CLUT[iColor] = (wG << 4 | wB) << 8 | wR;
  1583.                                     }
  1584.                                 }
  1585.  
  1586.                                 // Make up the RBG chunky buffer
  1587.                                 for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1588.                                    for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile ++)
  1589.                                        *((UWORD *) (uTile + (iXtile + iYtile * XDC_TILE) * 2)) = CLUT[pBuffer[iCnt + iXtile + (jCnt + iYtile) * iWidth]];
  1590.         
  1591.                                 // Send framebuffer update pixel data
  1592.                                 if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * 2, 0)))
  1593.                                 { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1594.  
  1595.                             }
  1596.                             else // Dumb screenmode or VVA
  1597.                             {
  1598.                                 if (iDepth > 1)
  1599.                                 {
  1600.                                     ReadPixelArray(uTile,     // Buffer
  1601.                                                0, 0,        // Dest X/Y in buffer
  1602.                                                XDC_TILE * XDC_C_MAXDEPTH,
  1603.                                                &(pActiveScreen -> RastPort),
  1604.                                                iCnt, jCnt,         // Source X/Y
  1605.                                                XDC_TILE, XDC_TILE,  // Source w/h
  1606.                                                RECTFMT_ARGB
  1607.                                                );
  1608.                     
  1609.                                     if (bVVA)
  1610.                                     {
  1611.                                         // Make the BGR233 buffer into uTile
  1612.                                         for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1613.                                            for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile ++)
  1614.                                         {
  1615.                                             uTile[iXtile + iYtile * XDC_TILE] =
  1616.                                                 (uTile[(iXtile  + iYtile * XDC_TILE) * 4 + 1] & 0xE0) >> 5 |
  1617.                                                 (uTile[(iXtile  + iYtile * XDC_TILE) * 4 + 2] & 0xE0) >> 2 |
  1618.                                                 (uTile[(iXtile  + iYtile * XDC_TILE) * 4 + 3] & 0xC0) >> 0;
  1619.                                         }
  1620.             
  1621.                                         // Send framebuffer update pixel data
  1622.                                         if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE, 0)))
  1623.                                         { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1624.                                     }
  1625.                                     else
  1626.                                     {
  1627.                                         // Send framebuffer update pixel data
  1628.                                         if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * XDC_C_MAXDEPTH, 0)))
  1629.                                         { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1630.                                     }
  1631.                                 }
  1632.                                 else // iDepth == 1 and VVA (Depth == 1 and not VVA is trated above)
  1633.                                 {
  1634.                                     // Once every 10 scans, refresh palette (we have no event here to say palette has changed)
  1635.                                     if (!(iUpdate++ % 10))
  1636.                                     {
  1637.                                         int iColor;
  1638.                                         for (iColor = 0 ; iColor < 256 ; iColor++)
  1639.                                         {
  1640.                                              ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor);
  1641.                                              UBYTE wR = (lColor >> 9) & 0x07;
  1642.                                              UBYTE wG = (lColor >> 5) & 0x07;
  1643.                                              UBYTE wB = (lColor >> 2) & 0x03;
  1644.                                              CLUT8[iColor] = (wB << 3 | wG) << 3 | wR;
  1645.                                         }
  1646.                                     }
  1647.                 
  1648.                                     // Make up the RBG chunky buffer
  1649.                                     for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++)
  1650.                                        for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile ++)
  1651.                                            uTile[iXtile + iYtile * XDC_TILE] = CLUT8[pBuffer[iCnt + iXtile + (jCnt + iYtile) * iWidth]];
  1652.         
  1653.                                     // Send framebuffer update pixel data
  1654.                                     if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE, 0)))
  1655.                                     { vCleanSession(XDC_SEND, Errno()); goto _NewSession; }
  1656.                                 }
  1657.                             }
  1658. #endif
  1659.                 }
  1660.             }
  1661.         }
  1662.     }
  1663.     
  1664.     vCleanSession("main : Session stop (child stopped)", 0);
  1665.     goto _NewSession;
  1666. }
  1667.